package com.elite.security.web;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @description:
 * @Author 万伟焕
 * @Date 2024-02-01 13:06:00
 **/
@Component
public class RouterSingleFilterChain {

	private static final Log logger = LogFactory.getLog(RouterSingleFilterChain.class);
	private volatile SingleFilterChain<SecurityFilterChain> mainChain;
	private volatile SingleFilterChain<SecurityFilterChain> backupChain;
	private volatile SingleFilterChain<SecurityFilterChain> currentChain;


	private final AtomicReference<List<SecurityFilterChain>> notifySecurityFilterChains = new AtomicReference<>();
	private final ReadWriteLock lock = new ReentrantReadWriteLock();

	public RouterSingleFilterChain(List<SecurityFilterChain> filterChains) {
		mainChain = new SingleFilterChain<SecurityFilterChain>(filterChains);
		backupChain = new SingleFilterChain<SecurityFilterChain>(filterChains);
		currentChain = new SingleFilterChain<SecurityFilterChain>(filterChains);
	}

	public void buildFilterChain(List<SecurityFilterChain> filterChains) {
		mainChain = new SingleFilterChain<SecurityFilterChain>(filterChains);
		backupChain = new SingleFilterChain<SecurityFilterChain>(filterChains);
		currentChain = new SingleFilterChain<SecurityFilterChain>(filterChains);
	}

	public RouterSingleFilterChain() {
	}

	public SingleFilterChain<SecurityFilterChain> getSingleFilterChain() {

		List<SecurityFilterChain> securityFilterChains = notifySecurityFilterChains.get();

		if (securityFilterChains != null && currentChain == backupChain) {
			return mainChain;
		}

		return currentChain;
	}

	public synchronized void setSecurityFilterChain(List<SecurityFilterChain> filterChains) {
		try {
			/***
			 * 把备份链 设置为 使用链 后续其它请求进来用备份链处理权限控制
			 */
			lock.writeLock().lock();
			currentChain = backupChain;
		} finally {

			lock.writeLock().unlock();
		}
		try {
			// 更新主链 安全过滤器链
			mainChain.getLock().writeLock().lock();
			// 刷新主链条
			mainChain.setFilterChains(filterChains);
		} catch (Throwable t) {
			logger.error("更新主链异常", t);
			throw t;
		} finally {
			mainChain.getLock().writeLock().unlock();
		}
		notifySecurityFilterChains.set(filterChains);
		try {
			lock.writeLock().lock();

			// 把主链条设置为 使用链条
			currentChain = mainChain;
			/**
			 *  设置 为null，表明安全过滤器链设置完成了，其它请求可以只要当前使用链了
			 */
			notifySecurityFilterChains.set(null);
		} finally {
			lock.writeLock().unlock();
		}
		try {
			backupChain.getLock().writeLock().lock();
			// refresh
			backupChain.setFilterChains(filterChains);
		} catch (Throwable t) {
			logger.error("更新备份链异常", t);
			throw t;
		} finally {
			backupChain.getLock().writeLock().unlock();
		}
	}
}
